/*!
 * Copyright (c) 2010 Jacob Essex
 *
 * Dual licenced under MIT or GPL 3 licneces
 * 
 * See the GPL3 or MIT files in the main directory for details
 */

require.def('pages/user/options',
['config', 'pages', 'lib/hashstring', 'se/api', 'db', 'db/sites', 'db/tags', 'db/answers', 'db/prediction'],
function(Config, Pages, Hashstring, Api, Db, Sites, Tags, Answers, Prediction){ 

    var callForAll = function(func, api, callbacks){
        var call = function(n){ callbacks && callbacks[n] && callbacks[n](); }
        var db = Db.getDb(Config.SiteDb);
        var chain = Db.chainWith(db)
        //all dbs that need to be created
        var databases = [Answers.QueuedAnswersDb, Tags.TagsDb,
                         Prediction.TagMapDb,
                         Prediction.PredictionDb];
         databases.forEach(function(v){
            chain.queue(v, func, [], 'success');
        });
        chain.success(function(){ call('success'); })
             .error(function(){ call('error'); })
             .exec();
    };

    return {
        destroyDatabases:function(api,callbacks){
            callForAll('destroy', api, callbacks);
        },
        createDatabases:function(api,callbacks){
            callForAll('create', api, callbacks);
        },
        /* ******************************************************************** */
        getTagInformation:function(api, callback){
            api.Tags({}, Api.from(0).until(function(tag){ return tag.count < Config.TagCountLimit; })).each({
                step:function(seTag){

                    callback && callback.step && callback.step();
                    
                    Db.chainWith(Db.getDb(Config.SiteDb))
                      .queue(Tags.TagsDb, 'exists', [seTag.name], 'no')
                      .queue(Tags.TagsDb, 'createTag', [], 'success', function(tx, tag){
                               tag.Name = seTag.name;
                               tag.Count = seTag.count;
                               tag.save(); 
                               return true;
                           })
                       .error(function(msg){ callback && callback.error && callback.error(msg); } )
                       .exec();
                   
                   },

                   done:function(){
                        callback && callback.done && callback.done();
                   },

                   error:function(code, msg){
                        callback && callback.error && callback.error(msg);
                   }
            
              
            });
        },

        /**
         * Gets the answer information and stores in the the database
         * @param callback an object with 3 optional functions
         *                  step: called about every time an answer is added
         *                  done: when the process is about finished
         *                  error: when an error occures
         */
        getAnswerInformation:function(api, userId, callback){
            var addAnswer = function(seans, errorFunc){
                var a = Answers.QueuedAnswersDb;
                Db.chainWith(Db.getDb(Config.SiteDb))
                  .queue(a, 'seAnswerExists', [seans.answer_id], 'no')
                  .queue(a, 'createAnswer', [], 'success', function(tx, answer){
                           answer.SeQuestionId = seans.question_id;
                           answer.SeAnswerId = seans.answer_id;

                           answer.UpVotes = seans.up_vote_count;
                           answer.DownVotes = seans.down_vote_count;

                           answer.save();
                           return true;
                       })
                  .error(errorFunc)
                  .exec();
            }

            var errorHandler = function(msg){
                callback && callback.error && callback.error(msg);
            }

            api.AnswersByUser({body:false}, userId, Api.from(0)).each({
                step:function(seans){
                    addAnswer(seans, errorHandler);
                    callback && callback.step && callback.step();
                },
                done:function(){
                    callback && callback.done && callback.done();
                },
                error:function(code, msg){
                    errorHandler(msg);
                }
            });
        },
        getQuestionInformation:function(api, count, callbacks){
            var errorHandler = function(msg){
                callbacks && callbacks.error && callbacks.error(msg);
            }

            //these are used to work out when we have done enough to call
            //the done function.
            var currentStepCount = 1;
            var endStepCount;

            var db = Db.getDb(Config.SiteDb);
            var preDb = new Prediction.PredictionDb(db);
            var ansDb = new Answers.QueuedAnswersDb(db);

            var addAnswerData = function(seQuestion){
                preDb.createAnswer(null, {
                    success:function(tx, predictAnswer){
                        ansDb.getByQuestionId(null, seQuestion.question_id, {
                            success:function(tx, ans){

                                //ignore if two answers to a question.
                                if ( ans.length > 1 ){
                                    return;
                                }
                                ans = ans[0];
                                predictAnswer.SeAnswerId = ans.SeAnswerId;
                                predictAnswer.SeQuestionId = seQuestion.question_id;
                                predictAnswer.UpVotes = ans.UpVotes;
                                predictAnswer.DownVotes = ans.DownVotes;

                                var title = seQuestion.title
                                                      .toLowerCase() 
                                                      .replace(/[^a-z0-9.+\s]/gi, '') //keep . for .net and + for c++
                                                      .replace(/\s+/g, ' ');

                                predictAnswer.QuestionTags = seQuestion.tags;
                                predictAnswer.InferredTags = title.split(' ');


                                predictAnswer.save(null, {
                                    success:function(){
                                        currentStepCount++;
                                        callbacks && callbacks.step && callbacks.step();
                                        if ( currentStepCount == endStepCount ){
                                            callbacks && callbacks.done && callbacks.done();
                                        }

                                    }
                                });
                            }
                        });
                    }
                });

            }

            
            preDb.count(null,{
                success:function(tx, dbCount){
                    //This is the amount of work that needs to be done. In other words the sample size
                    var loopTill = count - dbCount;
                    if ( loopTill <= 0 ){
                        callbacks && callbacks.done && callbacks.done();
                        return;
                    }
                    ansDb.getAnswers(null, {
                        success:function(tx, answers){


                            var answerIds = [];
                            for ( var i = 0; i < loopTill && i < answers.length; i++ ){
                                answerIds.push(answers[i].SeQuestionId);
                                answers[i].Added = 1;
                                answers[i].save();
                            }

                            if ( answerIds.length == 0 ){
                                callbacks && callbacks.done && callbacks.done();
                                return;
                            }
                            endStepCount = answerIds.length;

                            
                           
                            /*
                            api.QuestionsById({}, answerIds, Api.from(0))
                                 .each({
                                    step:addAnswerData,
                                    error:errorHandler
                                });
                                 */
                            var items = [];
                            while ( answerIds.length > 0 ){
                                var a = answerIds.length > 50 ? 50 : answerIds.length;
                                items.push(answerIds.splice(0, a));
                            }

                            function getQuestionSubset(){
                                if ( items.length == 0 ){
                                    return;
                                }
                                subset = items.pop();
                                api.QuestionsById({}, subset, Api.from(0))
                                     .each({
                                        step:addAnswerData,
                                        done:function(){
                                            setTimeout(getQuestionSubset, 1000);
                                        },
                                        error:errorHandler
                                    });
                            }
                            getQuestionSubset();

                            
                        },
                        error:errorHandler
                    });
                },
                error:errorHandler
            });


        }
    }
});
